home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 16 / AMIGAplus Sonderheft 16 (1998)(ICP)(DE)[!].iso / pd / anwendungen / ispell-3.1.18src / correct.c < prev    next >
C/C++ Source or Header  |  1995-07-03  |  44KB  |  1,715 lines

  1. #ifndef lint
  2. static char Rcs_Id[] =
  3.     "$Id: correct.c 1.58  1994/11/02  06:56:00  geoff Exp $";
  4. #endif
  5.  
  6. /*
  7.  * correct.c - Routines to manage the higher-level aspects of spell-checking
  8.  *
  9.  * This code originally resided in ispell.c, but was moved here to keep
  10.  * file sizes smaller.
  11.  *
  12.  * Copyright (c), 1983, by Pace Willisson
  13.  *
  14.  * Copyright 1992, 1993, Geoff Kuenning, Granada Hills, CA
  15.  * All rights reserved.
  16.  *
  17.  * Redistribution and use in source and binary forms, with or without
  18.  * modification, are permitted provided that the following conditions
  19.  * are met:
  20.  *
  21.  * 1. Redistributions of source code must retain the above copyright
  22.  *    notice, this list of conditions and the following disclaimer.
  23.  * 2. Redistributions in binary form must reproduce the above copyright
  24.  *    notice, this list of conditions and the following disclaimer in the
  25.  *    documentation and/or other materials provided with the distribution.
  26.  * 3. All modifications to the source code must be clearly marked as
  27.  *    such.  Binary redistributions based on modified source code
  28.  *    must be clearly marked as modified versions in the documentation
  29.  *    and/or other materials provided with the distribution.
  30.  * 4. All advertising materials mentioning features or use of this software
  31.  *    must display the following acknowledgment:
  32.  *      This product includes software developed by Geoff Kuenning and
  33.  *      other unpaid contributors.
  34.  * 5. The name of Geoff Kuenning may not be used to endorse or promote
  35.  *    products derived from this software without specific prior
  36.  *    written permission.
  37.  *
  38.  * THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
  39.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  40.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  41.  * ARE DISCLAIMED.  IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
  42.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  43.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  44.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  45.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  46.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  47.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  48.  * SUCH DAMAGE.
  49.  */
  50.  
  51. /*
  52.  * $Log: correct.c $
  53.  * Revision 1.58  1994/11/02  06:56:00  geoff
  54.  * Remove the anyword feature, which I've decided is a bad idea.
  55.  *
  56.  * Revision 1.57  1994/10/26  05:12:39  geoff
  57.  * Try boundary characters when inserting or substituting letters, except
  58.  * (naturally) at word boundaries.
  59.  *
  60.  * Revision 1.56  1994/10/25  05:46:30  geoff
  61.  * Fix an assignment inside a conditional that could generate spurious
  62.  * warnings (as well as being bad style).  Add support for the FF_ANYWORD
  63.  * option.
  64.  *
  65.  * Revision 1.55  1994/09/16  04:48:24  geoff
  66.  * Don't pass newlines from the input to various other routines, and
  67.  * don't assume that those routines leave the input unchanged.
  68.  *
  69.  * Revision 1.54  1994/09/01  06:06:41  geoff
  70.  * Change erasechar/killchar to uerasechar/ukillchar to avoid
  71.  * shared-library problems on HP systems.
  72.  *
  73.  * Revision 1.53  1994/08/31  05:58:38  geoff
  74.  * Add code to handle extremely long lines in -a mode without splitting
  75.  * words or reporting incorrect offsets.
  76.  *
  77.  * Revision 1.52  1994/05/25  04:29:24  geoff
  78.  * Fix a bug that caused line widths to be calculated incorrectly when
  79.  * displaying lines containing tabs.  Fix a couple of places where
  80.  * characters were sign-extended incorrectly, which could cause 8-bit
  81.  * characters to be displayed wrong.
  82.  *
  83.  * Revision 1.51  1994/05/17  06:44:05  geoff
  84.  * Add support for controlled compound formation and the COMPOUNDONLY
  85.  * option to affix flags.
  86.  *
  87.  * Revision 1.50  1994/04/27  05:20:14  geoff
  88.  * Allow compound words to be formed from more than two components
  89.  *
  90.  * Revision 1.49  1994/04/27  01:50:31  geoff
  91.  * Add support to correctly capitalize words generated as a result of a
  92.  * missing-space suggestion.
  93.  *
  94.  * Revision 1.48  1994/04/03  23:23:02  geoff
  95.  * Clean up the code in missingspace() to be a bit simpler and more
  96.  * efficient.
  97.  *
  98.  * Revision 1.47  1994/03/15  06:24:23  geoff
  99.  * Fix the +/-/~ commands to be independent.  Allow the + command to
  100.  * receive a suffix which is a deformatter type (currently hardwired to
  101.  * be either tex or nroff/troff).
  102.  *
  103.  * Revision 1.46  1994/02/21  00:20:03  geoff
  104.  * Fix some bugs that could cause bad displays in the interaction between
  105.  * TeX parsing and string characters.  Show_char now will not overrun
  106.  * the inverse-video display area by accident.
  107.  *
  108.  * Revision 1.45  1994/02/14  00:34:51  geoff
  109.  * Fix correct to accept length parameters for ctok and itok, so that it
  110.  * can pass them to the to/from ichar routines.
  111.  *
  112.  * Revision 1.44  1994/01/25  07:11:22  geoff
  113.  * Get rid of all old RCS log lines in preparation for the 3.1 release.
  114.  *
  115.  */
  116.  
  117. #include <ctype.h>
  118. #include "config.h"
  119. #include "ispell.h"
  120. #include "proto.h"
  121. #include "msgs.h"
  122.  
  123. #ifdef AMIGA
  124. extern char * Version_ID[];
  125. #else
  126. #include "version.h"
  127. #endif
  128.  
  129. void        givehelp P ((int interactive));
  130. void        checkfile P ((void));
  131. void        correct P ((char * ctok, int ctokl, ichar_t * itok, int itokl,
  132.           char ** curchar));
  133. static void    show_line P ((char * line, char * invstart, int invlen));
  134. static int    show_char P ((char ** cp, int linew, int output, int maxw));
  135. static int    line_size P ((char * buf, char * bufend));
  136. static void    inserttoken P ((char * buf, char * start, char * tok,
  137.           char ** curchar));
  138. static int    posscmp P ((char * a, char * b));
  139. int        casecmp P ((char * a, char * b, int canonical));
  140. void        makepossibilities P ((ichar_t * word));
  141. static int    insert P ((ichar_t * word));
  142. #ifndef NO_CAPITALIZATION_SUPPORT
  143. static void    wrongcapital P ((ichar_t * word));
  144. #endif /* NO_CAPITALIZATION_SUPPORT */
  145. static void    wrongletter P ((ichar_t * word));
  146. static void    extraletter P ((ichar_t * word));
  147. static void    missingletter P ((ichar_t * word));
  148. static void    missingspace P ((ichar_t * word));
  149. int        compoundgood P ((ichar_t * word, int pfxopts));
  150. static void    transposedletter P ((ichar_t * word));
  151. static void    tryveryhard P ((ichar_t * word));
  152. static int    ins_cap P ((ichar_t * word, ichar_t * pattern));
  153. static int    save_cap P ((ichar_t * word, ichar_t * pattern,
  154.           ichar_t savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN]));
  155. int        ins_root_cap P ((ichar_t * word, ichar_t * pattern,
  156.           int prestrip, int preadd, int sufstrip, int sufadd,
  157.           struct dent * firstdent, struct flagent * pfxent,
  158.           struct flagent * sufent));
  159. static void    save_root_cap P ((ichar_t * word, ichar_t * pattern,
  160.           int prestrip, int preadd, int sufstrip, int sufadd,
  161.           struct dent * firstdent, struct flagent * pfxent,
  162.           struct flagent * sufent,
  163.           ichar_t savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN],
  164.           int * nsaved));
  165. static char *    getline P ((char * buf));
  166. void        askmode P ((void));
  167. void        copyout P ((char ** cc, int cnt));
  168. static void    lookharder P ((char * string));
  169. #ifdef REGEX_LOOKUP
  170. static void    regex_dict_lookup P ((char * cmd, char * grepstr));
  171. #endif /* REGEX_LOOKUP */
  172.  
  173. void givehelp (interactive)
  174.     int            interactive;    /* NZ for interactive-mode help */
  175.     {
  176. #ifdef COMMANDFORSPACE
  177.     char ch;
  178. #endif
  179.     register FILE *helpout;    /* File to write help to */
  180.  
  181.     if (interactive)
  182.     {
  183.     erase ();
  184.     helpout = stdout;
  185.     }
  186.     else
  187.     helpout = stderr;
  188.  
  189.     (void) fprintf (helpout, CORR_C_HELP_1);
  190.     (void) fprintf (helpout, CORR_C_HELP_2);
  191.     (void) fprintf (helpout, CORR_C_HELP_3);
  192.     (void) fprintf (helpout, CORR_C_HELP_4);
  193.     (void) fprintf (helpout, CORR_C_HELP_5);
  194.     (void) fprintf (helpout, CORR_C_HELP_6);
  195.     (void) fprintf (helpout, CORR_C_HELP_7);
  196.     (void) fprintf (helpout, CORR_C_HELP_8);
  197.     (void) fprintf (helpout, CORR_C_HELP_9);
  198.  
  199.     (void) fprintf (helpout, CORR_C_HELP_COMMANDS);
  200.  
  201.     (void) fprintf (helpout, CORR_C_HELP_R_CMD);
  202.     (void) fprintf (helpout, CORR_C_HELP_BLANK);
  203.     (void) fprintf (helpout, CORR_C_HELP_A_CMD);
  204.     (void) fprintf (helpout, CORR_C_HELP_I_CMD);
  205.     (void) fprintf (helpout, CORR_C_HELP_U_CMD);
  206.     (void) fprintf (helpout, CORR_C_HELP_0_CMD);
  207.     (void) fprintf (helpout, CORR_C_HELP_L_CMD);
  208.     (void) fprintf (helpout, CORR_C_HELP_X_CMD);
  209.     (void) fprintf (helpout, CORR_C_HELP_Q_CMD);
  210.     (void) fprintf (helpout, CORR_C_HELP_BANG);
  211.     (void) fprintf (helpout, CORR_C_HELP_REDRAW);
  212.     (void) fprintf (helpout, CORR_C_HELP_SUSPEND);
  213.     (void) fprintf (helpout, CORR_C_HELP_HELP);
  214.  
  215.     if (interactive)
  216.     {
  217.     (void) fprintf (helpout, "\r\n\r\n");
  218.     (void) fprintf (helpout, CORR_C_HELP_TYPE_SPACE);
  219.     (void) fflush (helpout);
  220. #ifdef COMMANDFORSPACE
  221.     ch = GETKEYSTROKE ();
  222.     if (ch != ' ' && ch != '\n' && ch != '\r')
  223.         (void) ungetc (ch, stdin);
  224. #else
  225.     while (GETKEYSTROKE () != ' ')
  226.         ;
  227. #endif
  228.     }
  229.     }
  230.  
  231. void checkfile ()
  232.     {
  233.     int        bufno;
  234.     int        bufsize;
  235.     int        ch;
  236.  
  237.     for (bufno = 0;  bufno < contextsize;  bufno++)
  238.     contextbufs[bufno][0] = '\0';
  239.  
  240.     for (  ;  ;  )
  241.     {
  242.     for (bufno = contextsize;  --bufno > 0;  )
  243.         (void) strcpy (contextbufs[bufno],
  244.           contextbufs[bufno - 1]);
  245.     if (quit)    /* quit can't be set in l mode */
  246.         {
  247.         while (fgets (contextbufs[0],
  248.           sizeof contextbufs[0], infile) != NULL)
  249.         (void) fputs (contextbufs[0], outfile);
  250.         break;
  251.         }
  252.     /*
  253.      * Only read in enough characters to fill half this buffer so that any
  254.      * corrections we make are not likely to cause an overflow.
  255.      */
  256.     if (fgets (contextbufs[0], (sizeof contextbufs[0]) / 2, infile)
  257.       == NULL)
  258.         break;
  259.     /*
  260.      * If we didn't read to end-of-line, we may have ended the
  261.      * buffer in the middle of a word.  So keep reading until we
  262.      * see some sort of character that can't possibly be part of a
  263.      * word. (or until the buffer is full, which fortunately isn't
  264.      * all that likely).
  265.      */
  266.     bufsize = strlen (contextbufs[0]);
  267.     if (bufsize == (sizeof contextbufs[0]) / 2 - 1)
  268.         {
  269.         ch = (unsigned char) contextbufs[0][bufsize - 1];
  270.         while (bufsize < sizeof contextbufs[0] - 1
  271.           &&  (iswordch ((ichar_t) ch)  ||  isboundarych ((ichar_t) ch)
  272.           ||  isstringstart (ch)))
  273.         {
  274.         ch = getc (infile);
  275.         if (ch == EOF)
  276.             break;
  277.         contextbufs[0][bufsize++] = (char) ch;
  278.         contextbufs[0][bufsize] = '\0';
  279.         }
  280.         }
  281.     checkline (outfile);
  282.     }
  283.     }
  284.  
  285. void correct (ctok, ctokl, itok, itokl, curchar)
  286.     char *        ctok;
  287.     int            ctokl;
  288.     ichar_t *        itok;
  289.     int            itokl;
  290.     char **        curchar;
  291.     {
  292.     register int    c;
  293.     register int    i;
  294.     int            col_ht;
  295.     int            ncols;
  296.     char *        start_l2;
  297.     char *        begintoken;
  298.  
  299.     begintoken = *curchar - strlen (ctok);
  300.  
  301.     if (icharlen (itok) <= minword)
  302.     return;            /* Accept very short words */
  303.  
  304. checkagain:
  305.     if (good (itok, 0, 0, 0, 0)  ||  compoundgood (itok, 0))
  306.     return;
  307.  
  308.     erase ();
  309.     (void) printf ("    %s", ctok);
  310.     if (currentfile)
  311.     (void) printf (CORR_C_FILE_LABEL, currentfile);
  312.     if (readonly)
  313.     (void) printf (" %s", CORR_C_READONLY);
  314.     (void) printf ("\r\n\r\n");
  315.  
  316.     makepossibilities (itok);
  317.  
  318.     /*
  319.      * Make sure we have enough room on the screen to hold the
  320.      * possibilities.  Reduce the list if necessary.  co / (maxposslen + 8)
  321.      * is the maximum number of columns that will fit.  col_ht is the
  322.      * height of the columns.  The constant 4 allows 2 lines (1 blank) at
  323.      * the top of the screen, plus another blank line between the
  324.      * columns and the context, plus a final blank line at the bottom
  325.      * of the screen for command entry (R, L, etc).
  326.      */
  327.     col_ht = li - contextsize - 4 - minimenusize;
  328.     ncols = co / (maxposslen + 8);
  329.     if (pcount > ncols * col_ht)
  330.     pcount = ncols * col_ht;
  331.  
  332. #ifdef EQUAL_COLUMNS
  333.     /*
  334.      * Equalize the column sizes.  The last column will be short.
  335.      */
  336.     col_ht = (pcount + ncols - 1) / ncols;
  337. #endif
  338.  
  339.     for (i = 0; i < pcount; i++)
  340.     {
  341. #ifdef BOTTOMCONTEXT
  342.     move (2 + (i % col_ht), (maxposslen + 8) * (i / col_ht));
  343. #else /* BOTTOMCONTEXT */
  344.     move (3 + contextsize + (i % col_ht), (maxposslen + 8) * (i / col_ht));
  345. #endif /* BOTTOMCONTEXT */
  346.     if (i >= easypossibilities)
  347.         (void) printf ("??: %s", possibilities[i]);
  348.     else if (easypossibilities >= 10  &&  i < 10)
  349.         (void) printf ("0%d: %s", i, possibilities[i]);
  350.     else
  351.         (void) printf ("%2d: %s", i, possibilities[i]);
  352.     }
  353.  
  354. #ifdef BOTTOMCONTEXT
  355.     move (li - contextsize - 1 - minimenusize, 0);
  356. #else /* BOTTOMCONTEXT */
  357.     move (2, 0);
  358. #endif /* BOTTOMCONTEXT */
  359.     for (i = contextsize;  --i > 0;  )
  360.     show_line (contextbufs[i], contextbufs[i], 0);
  361.  
  362.     start_l2 = contextbufs[0];
  363.     if (line_size (contextbufs[0], *curchar) > co - (sg << 1) - 1)
  364.     {
  365.     start_l2 = begintoken - (co / 2);
  366.     while (start_l2 < begintoken)
  367.         {
  368.         i = line_size (start_l2, *curchar) + 1;
  369.         if (i + (sg << 1) <= co)
  370.         break;
  371.         start_l2 += i - co;
  372.         }
  373.     if (start_l2 > begintoken)
  374.         start_l2 = begintoken;
  375.     if (start_l2 < contextbufs[0])
  376.         start_l2 = contextbufs[0];
  377.     }
  378.     show_line (start_l2, begintoken, (int) strlen (ctok));
  379.  
  380.     if (minimenusize != 0)
  381.     {
  382.     move (li - 2, 0);
  383.     (void) printf (CORR_C_MINI_MENU);
  384.     }
  385.  
  386.     for (  ;  ;  )
  387.     {
  388.     (void) fflush (stdout);
  389.     switch (c = (GETKEYSTROKE () & NOPARITY))
  390.         {
  391.         case 'Z' & 037:
  392.         stop ();
  393.         erase ();
  394.         goto checkagain;
  395.         case ' ':
  396.         erase ();
  397.         (void) fflush (stdout);
  398.         return;
  399.         case 'q': case 'Q':
  400.         if (changes)
  401.             {
  402.             (void) printf (CORR_C_CONFIRM_QUIT);
  403.             (void) fflush (stdout);
  404.             c = (GETKEYSTROKE () & NOPARITY);
  405.             }
  406.         else
  407.             c = 'y';
  408.         if (c == 'y' || c == 'Y')
  409.             {
  410.             erase ();
  411.             (void) fflush (stdout);
  412.             done (0);
  413.             }
  414.         goto checkagain;
  415.         case 'i': case 'I':
  416.         treeinsert (ichartosstr (strtosichar (ctok, 0), 1),
  417.          ICHARTOSSTR_SIZE, 1);
  418.         erase ();
  419.         (void) fflush (stdout);
  420.         changes = 1;
  421.         return;
  422.         case 'u': case 'U':
  423.         itok = strtosichar (ctok, 0);
  424.         lowcase (itok);
  425.         treeinsert (ichartosstr (itok, 1), ICHARTOSSTR_SIZE, 1);
  426.         erase ();
  427.         (void) fflush (stdout);
  428.         changes = 1;
  429.         return;
  430.         case 'a': case 'A':
  431.         treeinsert (ichartosstr (strtosichar (ctok, 0), 1),
  432.           ICHARTOSSTR_SIZE, 0);
  433.         erase ();
  434.         (void) fflush (stdout);
  435.         return;
  436.         case 'L' & 037:
  437.         goto checkagain;
  438.         case '?':
  439.         givehelp (1);
  440.         goto checkagain;
  441.         case '!':
  442.         {
  443.         char    buf[200];
  444.  
  445.         move (li - 1, 0);
  446.         (void) putchar ('!');
  447.         if (getline (buf) == NULL)
  448.             {
  449.             (void) putchar (7);
  450.             erase ();
  451.             (void) fflush (stdout);
  452.             goto checkagain;
  453.             }
  454.         (void) printf ("\r\n");
  455.         (void) fflush (stdout);
  456. #ifdef    USESH
  457.         shescape (buf);
  458. #else
  459.         (void) shellescape (buf);
  460. #endif
  461.         erase ();
  462.         goto checkagain;
  463.         }
  464.         case 'r': case 'R':
  465.         move (li - 1, 0);
  466.         if (readonly)
  467.             {
  468.             (void) putchar (7);
  469.             (void) printf ("%s ", CORR_C_READONLY);
  470.             }
  471.         (void) printf (CORR_C_REPLACE_WITH);
  472.         if (getline (ctok) == NULL)
  473.             {
  474.             (void) putchar (7);
  475.             /* Put it back */
  476.             (void) ichartostr (ctok, itok, ctokl, 0);
  477.             }
  478.         else
  479.             {
  480.             inserttoken (contextbufs[0],
  481.               begintoken, ctok, curchar);
  482.             if (strtoichar (itok, ctok, itokl, 0))
  483.             {
  484.             (void) putchar (7);
  485.             (void) printf (WORD_TOO_LONG (ctok));
  486.             }
  487.             changes = 1;
  488.             }
  489.         erase ();
  490.         if (icharlen (itok) <= minword)
  491.             return;        /* Accept very short replacements */
  492.         goto checkagain;
  493.         case '0': case '1': case '2': case '3': case '4':
  494.         case '5': case '6': case '7': case '8': case '9':
  495.         i = c - '0';
  496.         if (easypossibilities >= 10)
  497.             {
  498.             c = GETKEYSTROKE () & NOPARITY;
  499.             if (c >= '0'  &&  c <= '9')
  500.             i = i * 10 + c - '0';
  501.             else if (c != '\r'  &&  c != '\n')
  502.             {
  503.             (void) putchar (7);
  504.             break;
  505.             }
  506.             }
  507.         if (i < easypossibilities)
  508.             {
  509.             (void) strcpy (ctok, possibilities[i]);
  510.             changes = 1;
  511.             inserttoken (contextbufs[0],
  512.             begintoken, ctok, curchar);
  513.             erase ();
  514.             if (readonly)
  515.             {
  516.             move (li - 1, 0);
  517.             (void) putchar (7);
  518.             (void) printf ("%s", CORR_C_READONLY);
  519.             (void) fflush (stdout);
  520.             (void) sleep ((unsigned) 2);
  521.             }
  522.             return;
  523.             }
  524.         (void) putchar (7);
  525.         break;
  526.         case '\r':    /* This makes typing \n after single digits */
  527.         case '\n':    /* ..less obnoxious */
  528.         break;
  529.         case 'l': case 'L':
  530.         {
  531.         char    buf[100];
  532.         move (li - 1, 0);
  533.         (void) printf (CORR_C_LOOKUP_PROMPT);
  534.         if (getline (buf) == NULL)
  535.             {
  536.             (void) putchar (7);
  537.             erase ();
  538.             goto checkagain;
  539.             }
  540.         (void) printf ("\r\n");
  541.         (void) fflush (stdout);
  542.         lookharder (buf);
  543.         erase ();
  544.         goto checkagain;
  545.         }
  546.         case 'x': case 'X':
  547.         quit = 1;
  548.         erase ();
  549.         (void) fflush (stdout);
  550.         return;
  551.         default:
  552.         (void) putchar (7);
  553.         break;
  554.         }
  555.     }
  556.     }
  557.  
  558. static void show_line (line, invstart, invlen)
  559.     char *        line;
  560.     register char *    invstart;
  561.     register int    invlen;
  562.     {
  563.     register int    width;
  564.  
  565.     width = invlen ? (sg << 1) : 0;
  566.     while (line < invstart  &&  width < co - 1)
  567.     width += show_char (&line, width, 1, invstart - line);
  568.     if (invlen)
  569.     {
  570.     inverse ();
  571.     invstart += invlen;
  572.     while (line < invstart  &&  width < co - 1)
  573.         width += show_char (&line, width, 1, invstart - line);
  574.     normal ();
  575.     }
  576.     while (*line  &&  width < co - 1)
  577.     width += show_char (&line, width, 1, 0);
  578.     (void) printf ("\r\n");
  579.     }
  580.  
  581. static int show_char (cp, linew, output, maxw)
  582.     register char **    cp;
  583.     int            linew;
  584.     int            output;        /* NZ to actually do output */
  585.     int            maxw;        /* NZ to limit width shown */
  586.     {
  587.     register int    ch;
  588.     register int    i;
  589.     int            len;
  590.     ichar_t        ichar;
  591.     register int    width;
  592.  
  593.     ch = (unsigned char) **cp;
  594.     if (l1_isstringch (*cp, len, 0))
  595.     ichar = SET_SIZE + laststringch;
  596.     else
  597.     ichar = chartoichar (ch);
  598.     if (!vflag  &&  iswordch (ichar)  &&  len == 1)
  599.     {
  600.     if (output)
  601.         (void) putchar (ch);
  602.     (*cp)++;
  603.     return 1;
  604.     }
  605.     if (ch == '\t')
  606.     {
  607.     if (output)
  608.         (void) putchar ('\t');
  609.     (*cp)++;
  610.     return 8 - (linew & 0x07);
  611.     }
  612.     /*
  613.      * Character is non-printing, or it's ISO and vflag is set.  Display
  614.      * it in "cat -v" form.  For string characters, display every element
  615.      * separately in that form.
  616.      */
  617.     width = 0;
  618.     if (maxw != 0  &&  len > maxw)
  619.     len = maxw;            /* Don't show too much */
  620.     for (i = 0;  i < len;  i++)
  621.     {
  622.     ch = (unsigned char) *(*cp)++;
  623.     if (ch > '\177')
  624.         {
  625.         if (output)
  626.         {
  627.         (void) putchar ('M');
  628.         (void) putchar ('-');
  629.         }
  630.         width += 2;
  631.         ch &= 0x7f;
  632.         }
  633.     if (ch < ' '  ||  ch == '\177')
  634.         {
  635.         if (output)
  636.         {
  637.         (void) putchar ('^');
  638.         if (ch == '\177')
  639.             (void) putchar ('?');
  640.         else
  641.             (void) putchar (ch + 'A' - '\001');
  642.         }
  643.         width += 2;
  644.         }
  645.     else
  646.         {
  647.         if (output)
  648.         (void) putchar (ch);
  649.         width += 1;
  650.         }
  651.     }
  652.     return width;
  653.     }
  654.  
  655. static int line_size (buf, bufend)
  656.     char *        buf;
  657.     register char *    bufend;
  658.     {
  659.     register int    width;
  660.  
  661.     for (width = 0;  buf < bufend  &&  *buf != '\0';  )
  662.     width += show_char (&buf, width, 0, bufend - buf);
  663.     return width;
  664.     }
  665.  
  666. static void inserttoken (buf, start, tok, curchar)
  667.     char *        buf;
  668.     char *        start; 
  669.     register char *    tok;
  670.     char **        curchar;
  671.     {
  672.     char        copy[BUFSIZ];
  673.     register char *    p;
  674.     register char *    q;
  675.     char *        ew;
  676.  
  677.     (void) strcpy (copy, buf);
  678.  
  679.     for (p = buf, q = copy; p != start; p++, q++)
  680.     *p = *q;
  681.     q += *curchar - start;
  682.     ew = skipoverword (tok);
  683.     while (tok < ew)
  684.     *p++ = *tok++;
  685.     *curchar = p;
  686.     if (*tok)
  687.     {
  688.  
  689.     /*
  690.     ** The token changed to two words.  Split it up and save the
  691.     ** second one for later.
  692.     */
  693.  
  694.     *p++ = *tok;
  695.     *tok++ = '\0';
  696.     while (*tok)
  697.         *p++ = *tok++;
  698.     }
  699.     while ((*p++ = *q++) != '\0')
  700.     ;
  701.     }
  702.  
  703. static int posscmp (a, b)
  704.     char *        a;
  705.     char *        b;
  706.     {
  707.  
  708.     return casecmp (a, b, 0);
  709.     }
  710.  
  711. int casecmp (a, b, canonical)
  712.     char *        a;
  713.     char *        b;
  714.     int            canonical;    /* NZ for canonical string chars */
  715.     {
  716.     register ichar_t *    ap;
  717.     register ichar_t *    bp;
  718.     ichar_t        inta[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];
  719.     ichar_t        intb[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];
  720.  
  721.     (void) strtoichar (inta, a, sizeof inta, canonical);
  722.     (void) strtoichar (intb, b, sizeof intb, canonical);
  723.     for (ap = inta, bp = intb;  *ap != 0;  ap++, bp++)
  724.     {
  725.     if (*ap != *bp)
  726.         {
  727.         if (*bp == '\0')
  728.         return hashheader.sortorder[*ap];
  729.         else if (mylower (*ap))
  730.         {
  731.         if (mylower (*bp)  ||  mytoupper (*ap) != *bp)
  732.             return (int) hashheader.sortorder[*ap]
  733.               - (int) hashheader.sortorder[*bp];
  734.         }
  735.         else
  736.         {
  737.         if (myupper (*bp)  ||  mytolower (*ap) != *bp)
  738.             return (int) hashheader.sortorder[*ap]
  739.               - (int) hashheader.sortorder[*bp];
  740.         }
  741.         }
  742.     }
  743.     if (*bp != '\0')
  744.     return -(int) hashheader.sortorder[*bp];
  745.     for (ap = inta, bp = intb;  *ap;  ap++, bp++)
  746.     {
  747.     if (*ap != *bp)
  748.         {
  749.         return (int) hashheader.sortorder[*ap]
  750.           - (int) hashheader.sortorder[*bp];
  751.         }
  752.     }
  753.     return 0;
  754.     }
  755.  
  756. void makepossibilities (word)
  757.     register ichar_t *    word;
  758.     {
  759.     register int    i;
  760.  
  761.     for (i = 0; i < MAXPOSSIBLE; i++)
  762.     possibilities[i][0] = 0;
  763.     pcount = 0;
  764.     maxposslen = 0;
  765.     easypossibilities = 0;
  766.  
  767. #ifndef NO_CAPITALIZATION_SUPPORT
  768.     wrongcapital (word);
  769. #endif
  770.  
  771. /* 
  772.  * according to Pollock and Zamora, CACM April 1984 (V. 27, No. 4),
  773.  * page 363, the correct order for this is:
  774.  * OMISSION = TRANSPOSITION > INSERTION > SUBSTITUTION
  775.  * thus, it was exactly backwards in the old version. -- PWP
  776.  */
  777.  
  778.     if (pcount < MAXPOSSIBLE)
  779.     missingletter (word);        /* omission */
  780.     if (pcount < MAXPOSSIBLE)
  781.     transposedletter (word);    /* transposition */
  782.     if (pcount < MAXPOSSIBLE)
  783.     extraletter (word);        /* insertion */
  784.     if (pcount < MAXPOSSIBLE)
  785.     wrongletter (word);        /* substitution */
  786.  
  787.     if ((compoundflag != COMPOUND_ANYTIME)  &&  pcount < MAXPOSSIBLE)
  788.     missingspace (word);    /* two words */
  789.  
  790.     easypossibilities = pcount;
  791.     if (easypossibilities == 0  ||  tryhardflag)
  792.     tryveryhard (word);
  793.  
  794.     if ((sortit  ||  (pcount > easypossibilities))  &&  pcount)
  795.     {
  796.     if (easypossibilities > 0  &&  sortit)
  797.         qsort ((char *) possibilities,
  798.           (unsigned) easypossibilities,
  799.           sizeof (possibilities[0]),
  800.           (int (*) P ((const void *, const void *))) posscmp);
  801.     if (pcount > easypossibilities)
  802.         qsort ((char *) &possibilities[easypossibilities][0],
  803.           (unsigned) (pcount - easypossibilities),
  804.           sizeof (possibilities[0]),
  805.           (int (*) P ((const void *, const void *))) posscmp);
  806.     }
  807.     }
  808.  
  809. static int insert (word)
  810.     register ichar_t *    word;
  811.     {
  812.     register int    i;
  813.     register char *    realword;
  814.  
  815.     realword = ichartosstr (word, 0);
  816.     for (i = 0; i < pcount; i++)
  817.     {
  818.     if (strcmp (possibilities[i], realword) == 0)
  819.         return (0);
  820.     }
  821.  
  822.     (void) strcpy (possibilities[pcount++], realword);
  823.     i = strlen (realword);
  824.     if (i > maxposslen)
  825.     maxposslen = i;
  826.     if (pcount >= MAXPOSSIBLE)
  827.     return (-1);
  828.     else
  829.     return (0);
  830.     }
  831.  
  832. #ifndef NO_CAPITALIZATION_SUPPORT
  833. static void wrongcapital (word)
  834.     register ichar_t *    word;
  835.     {
  836.     ichar_t        newword[INPUTWORDLEN + MAXAFFIXLEN];
  837.  
  838.     /*
  839.     ** When the third parameter to "good" is nonzero, it ignores
  840.     ** case.  If the word matches this way, "ins_cap" will recapitalize
  841.     ** it correctly.
  842.     */
  843.     if (good (word, 0, 1, 0, 0))
  844.     {
  845.     (void) icharcpy (newword, word);
  846.     upcase (newword);
  847.     (void) ins_cap (newword, word);
  848.     }
  849.     }
  850. #endif
  851.  
  852. static void wrongletter (word)
  853.     register ichar_t *    word;
  854.     {
  855.     register int    i;
  856.     register int    j;
  857.     register int    n;
  858.     ichar_t        savechar;
  859.     ichar_t        newword[INPUTWORDLEN + MAXAFFIXLEN];
  860.  
  861.     n = icharlen (word);
  862.     (void) icharcpy (newword, word);
  863. #ifndef NO_CAPITALIZATION_SUPPORT
  864.     upcase (newword);
  865. #endif
  866.  
  867.     for (i = 0; i < n; i++)
  868.     {
  869.     savechar = newword[i];
  870.     for (j=0; j < Trynum; ++j)
  871.         {
  872.         if (Try[j] == savechar)
  873.         continue;
  874.         else if (isboundarych (Try[j])  &&  (i == 0  ||  i == n - 1))
  875.         continue;
  876.         newword[i] = Try[j];
  877.         if (good (newword, 0, 1, 0, 0))
  878.         {
  879.         if (ins_cap (newword, word) < 0)
  880.             return;
  881.         }
  882.         }
  883.     newword[i] = savechar;
  884.     }
  885.     }
  886.  
  887. static void extraletter (word)
  888.     register ichar_t *    word;
  889.     {
  890.     ichar_t        newword[INPUTWORDLEN + MAXAFFIXLEN];
  891.     register ichar_t *    p;
  892.     register ichar_t *    r;
  893.  
  894.     if (icharlen (word) < 2)
  895.     return;
  896.  
  897.     (void) icharcpy (newword, word + 1);
  898.     for (p = word, r = newword;  *p != 0;  )
  899.     {
  900.     if (good (newword, 0, 1, 0, 0))
  901.         {
  902.         if (ins_cap (newword, word) < 0)
  903.         return;
  904.         }
  905.     *r++ = *p++;
  906.     }
  907.     }
  908.  
  909. static void missingletter (word)
  910.     ichar_t *        word;
  911.     {
  912.     ichar_t        newword[INPUTWORDLEN + MAXAFFIXLEN + 1];
  913.     register ichar_t *    p;
  914.     register ichar_t *    r;
  915.     register int    i;
  916.  
  917.     (void) icharcpy (newword + 1, word);
  918.     for (p = word, r = newword;  *p != 0;  )
  919.     {
  920.     for (i = 0;  i < Trynum;  i++)
  921.         {
  922.         if (isboundarych (Try[i])  &&  r == newword)
  923.         continue;
  924.         *r = Try[i];
  925.         if (good (newword, 0, 1, 0, 0))
  926.         {
  927.         if (ins_cap (newword, word) < 0)
  928.             return;
  929.         }
  930.         }
  931.     *r++ = *p++;
  932.     }
  933.     for (i = 0;  i < Trynum;  i++)
  934.     {
  935.     if (isboundarych (Try[i]))
  936.         continue;
  937.     *r = Try[i];
  938.     if (good (newword, 0, 1, 0, 0))
  939.         {
  940.         if (ins_cap (newword, word) < 0)
  941.         return;
  942.         }
  943.     }
  944.     }
  945.  
  946. static void missingspace (word)
  947.     ichar_t *        word;
  948.     {
  949.     ichar_t        firsthalf[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
  950.     int            firstno;    /* Index into first */
  951.     ichar_t *        firstp;        /* Ptr into current firsthalf word */
  952.     ichar_t        newword[INPUTWORDLEN + MAXAFFIXLEN + 1];
  953.     int            nfirsthalf;    /* No. words saved in 1st half */
  954.     int            nsecondhalf;    /* No. words saved in 2nd half */
  955.     register ichar_t *    p;
  956.     ichar_t        secondhalf[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
  957.     int            secondno;    /* Index into second */
  958.  
  959.     /*
  960.     ** We don't do words of length less than 3;  this keeps us from
  961.     ** splitting all two-letter words into two single letters.  We
  962.     ** also don't do maximum-length words, since adding the space
  963.     ** would exceed the size of the "possibilities" array.
  964.     */
  965.     nfirsthalf = icharlen (word);
  966.     if (nfirsthalf < 3  ||  nfirsthalf >= INPUTWORDLEN + MAXAFFIXLEN - 1)
  967.     return;
  968.     (void) icharcpy (newword + 1, word);
  969.     for (p = newword + 1;  p[1] != '\0';  p++)
  970.     {
  971.     p[-1] = *p;
  972.     *p = '\0';
  973.     if (good (newword, 0, 1, 0, 0))
  974.         {
  975.         /*
  976.          * Save_cap must be called before good() is called on the
  977.          * second half, because it uses state left around by
  978.          * good().  This is unfortunate because it wastes a bit of
  979.          * time, but I don't think it's a significant performance
  980.          * problem.
  981.          */
  982.         nfirsthalf = save_cap (newword, word, firsthalf);
  983.         if (good (p + 1, 0, 1, 0, 0))
  984.         {
  985.         nsecondhalf = save_cap (p + 1, p + 1, secondhalf);
  986.         for (firstno = 0;  firstno < nfirsthalf;  firstno++)
  987.             {
  988.             firstp = &firsthalf[firstno][p - newword];
  989.             for (secondno = 0;  secondno < nsecondhalf;  secondno++)
  990.             {
  991.             *firstp = ' ';
  992.             (void) icharcpy (firstp + 1, secondhalf[secondno]);
  993.             if (insert (firsthalf[firstno]) < 0)
  994.                 return;
  995.             *firstp = '-';
  996.             if (insert (firsthalf[firstno]) < 0)
  997.                 return;
  998.             }
  999.             }
  1000.         }
  1001.         }
  1002.     }
  1003.     }
  1004.  
  1005. int compoundgood (word, pfxopts)
  1006.     ichar_t *        word;
  1007.     int            pfxopts;    /* Options to apply to prefixes */
  1008.     {
  1009.     ichar_t        newword[INPUTWORDLEN + MAXAFFIXLEN];
  1010.     register ichar_t *    p;
  1011.     register ichar_t    savech;
  1012.     long        secondcap;    /* Capitalization of 2nd half */
  1013.  
  1014.     /*
  1015.     ** If compoundflag is COMPOUND_NEVER, compound words are never ok.
  1016.     */
  1017.     if (compoundflag == COMPOUND_NEVER)
  1018.     return 0;
  1019.     /*
  1020.     ** Test for a possible compound word (for languages like German that
  1021.     ** form lots of compounds).
  1022.     **
  1023.     ** This is similar to missingspace, except we quit on the first hit,
  1024.     ** and we won't allow either member of the compound to be a single
  1025.     ** letter.
  1026.     **
  1027.     ** We don't do words of length less than 2 * compoundmin, since
  1028.     ** both halves must at least compoundmin letters.
  1029.     */
  1030.     if (icharlen (word) < 2 * hashheader.compoundmin)
  1031.     return 0;
  1032.     (void) icharcpy (newword, word);
  1033.     p = newword + hashheader.compoundmin;
  1034.     for (  ;  p[hashheader.compoundmin - 1] != 0;  p++)
  1035.     {
  1036.     savech = *p;
  1037.     *p = 0;
  1038.     if (good (newword, 0, 0, pfxopts, FF_COMPOUNDONLY))
  1039.         {
  1040.         *p = savech;
  1041.         if (good (p, 0, 1, FF_COMPOUNDONLY, 0)
  1042.           ||  compoundgood (p, FF_COMPOUNDONLY))
  1043.         {
  1044.         secondcap = whatcap (p);
  1045.         switch (whatcap (newword))
  1046.             {
  1047.             case ANYCASE:
  1048.             case CAPITALIZED:
  1049.             case FOLLOWCASE:    /* Followcase can have l.c. suffix */
  1050.             return secondcap == ANYCASE;
  1051.             case ALLCAPS:
  1052.             return secondcap == ALLCAPS;
  1053.             }
  1054.         }
  1055.         }
  1056.     else
  1057.         *p = savech;
  1058.     }
  1059.     return 0;
  1060.     }
  1061.  
  1062. static void transposedletter (word)
  1063.     register ichar_t *    word;
  1064.     {
  1065.     ichar_t        newword[INPUTWORDLEN + MAXAFFIXLEN];
  1066.     register ichar_t *    p;
  1067.     register ichar_t    temp;
  1068.  
  1069.     (void) icharcpy (newword, word);
  1070.     for (p = newword;  p[1] != 0;  p++)
  1071.     {
  1072.     temp = *p;
  1073.     *p = p[1];
  1074.     p[1] = temp;
  1075.     if (good (newword, 0, 1, 0, 0))
  1076.         {
  1077.         if (ins_cap (newword, word) < 0)
  1078.         return;
  1079.         }
  1080.     temp = *p;
  1081.     *p = p[1];
  1082.     p[1] = temp;
  1083.     }
  1084.     }
  1085.  
  1086. static void tryveryhard (word)
  1087.     ichar_t *        word;
  1088.     {
  1089.     (void) good (word, 1, 0, 0, 0);
  1090.     }
  1091.  
  1092. /* Insert one or more correctly capitalized versions of word */
  1093. static int ins_cap (word, pattern)
  1094.     ichar_t *        word;
  1095.     ichar_t *        pattern;
  1096.     {
  1097.     int            i;        /* Index into savearea */
  1098.     int            nsaved;        /* No. of words saved */
  1099.     ichar_t        savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
  1100.  
  1101.     nsaved = save_cap (word, pattern, savearea);
  1102.     for (i = 0;  i < nsaved;  i++)
  1103.     {
  1104.     if (insert (savearea[i]) < 0)
  1105.         return -1;
  1106.     }
  1107.     return 0;
  1108.     }
  1109.  
  1110. /* Save one or more correctly capitalized versions of word */
  1111. static int save_cap (word, pattern, savearea)
  1112.     ichar_t *        word;        /* Word to save */
  1113.     ichar_t *        pattern;    /* Prototype capitalization pattern */
  1114.     ichar_t        savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
  1115.                     /* Room to save words */
  1116.     {
  1117.     int            hitno;        /* Index into hits array */
  1118.     int            nsaved;        /* Number of words saved */
  1119.     int            preadd;        /* No. chars added to front of root */
  1120.     int            prestrip;    /* No. chars stripped from front */
  1121.     int            sufadd;        /* No. chars added to back of root */
  1122.     int            sufstrip;    /* No. chars stripped from back */
  1123.  
  1124.     if (*word == 0)
  1125.     return 0;
  1126.  
  1127.     for (hitno = numhits, nsaved = 0;  --hitno >= 0  &&  nsaved < MAX_CAPS;  )
  1128.     {
  1129.     if (hits[hitno].prefix)
  1130.         {
  1131.         prestrip = hits[hitno].prefix->stripl;
  1132.         preadd = hits[hitno].prefix->affl;
  1133.         }
  1134.     else
  1135.         prestrip = preadd = 0;
  1136.     if (hits[hitno].suffix)
  1137.         {
  1138.         sufstrip = hits[hitno].suffix->stripl;
  1139.         sufadd = hits[hitno].suffix->affl;
  1140.         }
  1141.     else
  1142.         sufadd = sufstrip = 0;
  1143.     save_root_cap (word, pattern, prestrip, preadd,
  1144.         sufstrip, sufadd,
  1145.         hits[hitno].dictent, hits[hitno].prefix, hits[hitno].suffix,
  1146.         savearea, &nsaved);
  1147.     }
  1148.     return nsaved;
  1149.     }
  1150.  
  1151. int ins_root_cap (word, pattern, prestrip, preadd, sufstrip, sufadd,
  1152.   firstdent, pfxent, sufent)
  1153.     register ichar_t *    word;
  1154.     register ichar_t *    pattern;
  1155.     int            prestrip;
  1156.     int            preadd;
  1157.     int            sufstrip;
  1158.     int            sufadd;
  1159.     struct dent *    firstdent;
  1160.     struct flagent *    pfxent;
  1161.     struct flagent *    sufent;
  1162.     {
  1163.     int            i;        /* Index into savearea */
  1164.     ichar_t        savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
  1165.     int            nsaved;        /* Number of words saved */
  1166.  
  1167.     nsaved = 0;
  1168.     save_root_cap (word, pattern, prestrip, preadd, sufstrip, sufadd,
  1169.       firstdent, pfxent, sufent, savearea, &nsaved);
  1170.     for (i = 0;  i < nsaved;  i++)
  1171.     {
  1172.     if (insert (savearea[i]) < 0)
  1173.         return -1;
  1174.     }
  1175.     return 0;
  1176.     }
  1177.  
  1178. /* ARGSUSED */
  1179. static void save_root_cap (word, pattern, prestrip, preadd, sufstrip, sufadd,
  1180.   firstdent, pfxent, sufent, savearea, nsaved)
  1181.     register ichar_t *    word;        /* Word to be saved */
  1182.     register ichar_t *    pattern;    /* Capitalization pattern */
  1183.     int            prestrip;    /* No. chars stripped from front */
  1184.     int            preadd;        /* No. chars added to front of root */
  1185.     int            sufstrip;    /* No. chars stripped from back */
  1186.     int            sufadd;        /* No. chars added to back of root */
  1187.     struct dent *    firstdent;    /* First dent for root */
  1188.     struct flagent *    pfxent;        /* Pfx-flag entry for word */
  1189.     struct flagent *    sufent;        /* Sfx-flag entry for word */
  1190.     ichar_t        savearea[MAX_CAPS][INPUTWORDLEN + MAXAFFIXLEN];
  1191.                     /* Room to save words */
  1192.     int *        nsaved;        /* Number saved so far (updated) */
  1193.     {
  1194. #ifndef NO_CAPITALIZATION_SUPPORT
  1195.     register struct dent * dent;
  1196. #endif /* NO_CAPITALIZATION_SUPPORT */
  1197.     int            firstisupper;
  1198.     ichar_t        newword[INPUTWORDLEN + 4 * MAXAFFIXLEN + 4];
  1199. #ifndef NO_CAPITALIZATION_SUPPORT
  1200.     register ichar_t *    p;
  1201.     int            len;
  1202.     int            i;
  1203.     int            limit;
  1204. #endif /* NO_CAPITALIZATION_SUPPORT */
  1205.  
  1206.     if (*nsaved >= MAX_CAPS)
  1207.     return;
  1208.     (void) icharcpy (newword, word);
  1209.     firstisupper = myupper (pattern[0]);
  1210. #ifdef NO_CAPITALIZATION_SUPPORT
  1211.     /*
  1212.     ** Apply the old, simple-minded capitalization rules.
  1213.     */
  1214.     if (firstisupper)
  1215.     {
  1216.     if (myupper (pattern[1]))
  1217.         upcase (newword);
  1218.     else
  1219.         {
  1220.         lowcase (newword);
  1221.         newword[0] = mytoupper (newword[0]);
  1222.         }
  1223.     }
  1224.     else
  1225.     lowcase (newword);
  1226.     (void) icharcpy (savearea[*nsaved], newword);
  1227.     (*nsaved)++;
  1228.     return;
  1229. #else /* NO_CAPITALIZATION_SUPPORT */
  1230. #define flagsareok(dent)    \
  1231.     ((pfxent == NULL \
  1232.     ||  TSTMASKBIT (dent->mask, pfxent->flagbit)) \
  1233.       &&  (sufent == NULL \
  1234.     ||  TSTMASKBIT (dent->mask, sufent->flagbit)))
  1235.  
  1236.     dent = firstdent;
  1237.     if ((dent->flagfield & (CAPTYPEMASK | MOREVARIANTS)) == ALLCAPS)
  1238.     {
  1239.     upcase (newword);    /* Uppercase required */
  1240.     (void) icharcpy (savearea[*nsaved], newword);
  1241.     (*nsaved)++;
  1242.     return;
  1243.     }
  1244.     for (p = pattern;  *p;  p++)
  1245.     {
  1246.     if (mylower (*p))
  1247.         break;
  1248.     }
  1249.     if (*p == 0)
  1250.     {
  1251.     upcase (newword);    /* Pattern was all caps */
  1252.     (void) icharcpy (savearea[*nsaved], newword);
  1253.     (*nsaved)++;
  1254.     return;
  1255.     }
  1256.     for (p = pattern + 1;  *p;  p++)
  1257.     {
  1258.     if (myupper (*p))
  1259.         break;
  1260.     }
  1261.     if (*p == 0)
  1262.     {
  1263.     /*
  1264.     ** The pattern was all-lower or capitalized.  If that's
  1265.     ** legal, insert only that version.
  1266.     */
  1267.     if (firstisupper)
  1268.         {
  1269.         if (captype (dent->flagfield) == CAPITALIZED
  1270.           ||  captype (dent->flagfield) == ANYCASE)
  1271.         {
  1272.         lowcase (newword);
  1273.         newword[0] = mytoupper (newword[0]);
  1274.         (void) icharcpy (savearea[*nsaved], newword);
  1275.         (*nsaved)++;
  1276.         return;
  1277.         }
  1278.         }
  1279.     else
  1280.         {
  1281.         if (captype (dent->flagfield) == ANYCASE)
  1282.         {
  1283.         lowcase (newword);
  1284.         (void) icharcpy (savearea[*nsaved], newword);
  1285.         (*nsaved)++;
  1286.         return;
  1287.         }
  1288.         }
  1289.     while (dent->flagfield & MOREVARIANTS)
  1290.         {
  1291.         dent = dent->next;
  1292.         if (captype (dent->flagfield) == FOLLOWCASE
  1293.           ||  !flagsareok (dent))
  1294.         continue;
  1295.         if (firstisupper)
  1296.         {
  1297.         if (captype (dent->flagfield) == CAPITALIZED)
  1298.             {
  1299.             lowcase (newword);
  1300.             newword[0] = mytoupper (newword[0]);
  1301.             (void) icharcpy (savearea[*nsaved], newword);
  1302.             (*nsaved)++;
  1303.             return;
  1304.             }
  1305.         }
  1306.         else
  1307.         {
  1308.         if (captype (dent->flagfield) == ANYCASE)
  1309.             {
  1310.             lowcase (newword);
  1311.             (void) icharcpy (savearea[*nsaved], newword);
  1312.             (*nsaved)++;
  1313.             return;
  1314.             }
  1315.         }
  1316.         }
  1317.     }
  1318.     /*
  1319.     ** Either the sample had complex capitalization, or the simple
  1320.     ** capitalizations (all-lower or capitalized) are illegal.
  1321.     ** Insert all legal capitalizations, including those that are
  1322.     ** all-lower or capitalized.  If the prototype is capitalized,
  1323.     ** capitalized all-lower samples.  Watch out for affixes.
  1324.     */
  1325.     dent = firstdent;
  1326.     p = strtosichar (dent->word, 1);
  1327.     len = icharlen (p);
  1328.     if (dent->flagfield & MOREVARIANTS)
  1329.     dent = dent->next;    /* Skip place-holder entry */
  1330.     for (  ;  ;  )
  1331.     {
  1332.     if (flagsareok (dent))
  1333.         {
  1334.         if (captype (dent->flagfield) != FOLLOWCASE)
  1335.         {
  1336.         lowcase (newword);
  1337.         if (firstisupper  ||  captype (dent->flagfield) == CAPITALIZED)
  1338.             newword[0] = mytoupper (newword[0]);
  1339.         (void) icharcpy (savearea[*nsaved], newword);
  1340.         (*nsaved)++;
  1341.         if (*nsaved >= MAX_CAPS)
  1342.             return;
  1343.         }
  1344.         else
  1345.         {
  1346.         /* Followcase is the tough one. */
  1347.         p = strtosichar (dent->word, 1);
  1348.         (void) bcopy ((char *) (p + prestrip),
  1349.           (char *) (newword + preadd),
  1350.           (len - prestrip - sufstrip) * sizeof (ichar_t));
  1351.         if (myupper (p[prestrip]))
  1352.             {
  1353.             for (i = 0;  i < preadd;  i++)
  1354.             newword[i] = mytoupper (newword[i]);
  1355.             }
  1356.         else
  1357.             {
  1358.             for (i = 0;  i < preadd;  i++)
  1359.             newword[i] = mytolower (newword[i]);
  1360.             }
  1361.         limit = len + preadd + sufadd - prestrip - sufstrip;
  1362.         i = len + preadd - prestrip - sufstrip;
  1363.         p += len - sufstrip - 1;
  1364.         if (myupper (*p))
  1365.             {
  1366.             for (p = newword + i;  i < limit;  i++, p++)
  1367.             *p = mytoupper (*p);
  1368.             }
  1369.         else
  1370.             {
  1371.             for (p = newword + i;  i < limit;  i++, p++)
  1372.               *p = mytolower (*p);
  1373.             }
  1374.         (void) icharcpy (savearea[*nsaved], newword);
  1375.         (*nsaved)++;
  1376.         if (*nsaved >= MAX_CAPS)
  1377.             return;
  1378.         }
  1379.         }
  1380.     if ((dent->flagfield & MOREVARIANTS) == 0)
  1381.         break;        /* End of the line */
  1382.     dent = dent->next;
  1383.     }
  1384.     return;
  1385. #endif /* NO_CAPITALIZATION_SUPPORT */
  1386.     }
  1387.  
  1388. static char * getline (s)
  1389.     register char *    s;
  1390.     {
  1391.     register char *    p;
  1392.     register int    c;
  1393.  
  1394.     p = s;
  1395.  
  1396.     for (  ;  ;  )
  1397.     {
  1398.     (void) fflush (stdout);
  1399.     c = (GETKEYSTROKE () & NOPARITY);
  1400.     if (c == '\\')
  1401.         {
  1402.         (void) putchar ('\\');
  1403.         (void) fflush (stdout);
  1404.         c = (GETKEYSTROKE () & NOPARITY);
  1405.         backup ();
  1406.         (void) putchar (c);
  1407.         *p++ = (char) c;
  1408.         }
  1409.     else if (c == ('G' & 037))
  1410.         return (NULL);
  1411.     else if (c == '\n' || c == '\r')
  1412.         {
  1413.         *p = 0;
  1414.         return (s);
  1415.         }
  1416.     else if (c == uerasechar)
  1417.         {
  1418.         if (p != s)
  1419.         {
  1420.         p--;
  1421.         backup ();
  1422.         (void) putchar (' ');
  1423.         backup ();
  1424.         }
  1425.         }
  1426.     else if (c == ukillchar)
  1427.         {
  1428.         while (p != s)
  1429.         {
  1430.         p--;
  1431.         backup ();
  1432.         (void) putchar (' ');
  1433.         backup ();
  1434.         }
  1435.         }
  1436.     else
  1437.         {
  1438.         *p++ = (char) c;
  1439.         (void) putchar (c);
  1440.         }
  1441.     }
  1442.     }
  1443.  
  1444. void askmode ()
  1445.     {
  1446.     int            bufsize;    /* Length of contextbufs[0] */
  1447.     int            ch;        /* Next character read from input */
  1448.     register char *    cp1;
  1449.     register char *    cp2;
  1450.     ichar_t *        itok;        /* Ichar version of current word */
  1451.     int            hadnl;        /* NZ if \n was at end of line */
  1452.  
  1453.     if (fflag)
  1454.     {
  1455.     if (freopen (askfilename, "w", stdout) == NULL)
  1456.         {
  1457.         (void) fprintf (stderr, CANT_CREATE, askfilename);
  1458.         exit (1);
  1459.         }
  1460.     }
  1461.  
  1462. #ifdef AMIGA
  1463.     (void) printf ("%s\n%s\n", Version_ID[0],Version_ID[2]);
  1464. #else
  1465.     (void) printf ("%s\n", Version_ID[0]);
  1466. #endif
  1467.  
  1468.     contextoffset = 0;
  1469.     while (1)
  1470.     {
  1471.     (void) fflush (stdout);
  1472.     /*
  1473.      * Only read in enough characters to fill half this buffer so that any
  1474.      * corrections we make are not likely to cause an overflow.
  1475.      */
  1476.     if (contextoffset == 0)
  1477.         {
  1478.         if (xgets (contextbufs[0], (sizeof contextbufs[0]) / 2, stdin)
  1479.           == NULL)
  1480.         break;
  1481.         }
  1482.     else
  1483.         {
  1484.         if (fgets (contextbufs[0], (sizeof contextbufs[0]) / 2, stdin)
  1485.           == NULL)
  1486.         break;
  1487.         }
  1488.     /*
  1489.      * If we didn't read to end-of-line, we may have ended the
  1490.      * buffer in the middle of a word.  So keep reading until we
  1491.      * see some sort of character that can't possibly be part of a
  1492.      * word. (or until the buffer is full, which fortunately isn't
  1493.      * all that likely).
  1494.      */
  1495.     bufsize = strlen (contextbufs[0]);
  1496.     if (contextbufs[0][bufsize - 1] == '\n')
  1497.         {
  1498.         hadnl = 1;
  1499.         contextbufs[0][--bufsize] = '\0';
  1500.         }
  1501.     else
  1502.         hadnl = 0;
  1503.     if (bufsize == (sizeof contextbufs[0]) / 2 - 1)
  1504.         {
  1505.         ch = (unsigned char) contextbufs[0][bufsize - 1];
  1506.         while (bufsize < sizeof contextbufs[0] - 1
  1507.           &&  (iswordch ((ichar_t) ch)  ||  isboundarych ((ichar_t) ch)
  1508.           ||  isstringstart (ch)))
  1509.         {
  1510.         ch = getc (stdin);
  1511.         if (ch == EOF)
  1512.             break;
  1513.         contextbufs[0][bufsize++] = (char) ch;
  1514.         contextbufs[0][bufsize] = '\0';
  1515.         }
  1516.         }
  1517.     /*
  1518.     ** *line is like `i', @line is like `a', &line is like 'u'
  1519.     ** `#' is like `Q' (writes personal dictionary)
  1520.     ** `+' sets tflag, `-' clears tflag
  1521.     ** `!' sets terse mode, `%' clears terse
  1522.     ** `~' followed by a filename sets parameters according to file name
  1523.     ** `^' causes rest of line to be checked after stripping 1st char
  1524.     */
  1525.     if (contextoffset != 0)
  1526.         checkline (stdout);
  1527.     else
  1528.         {
  1529.         if (contextbufs[0][0] == '*'  ||  contextbufs[0][0] == '@')
  1530.         treeinsert(ichartosstr (strtosichar (contextbufs[0] + 1, 0), 1),
  1531.           ICHARTOSSTR_SIZE,
  1532.           contextbufs[0][0] == '*');
  1533.         else if (contextbufs[0][0] == '&')
  1534.         {
  1535.         itok = strtosichar (contextbufs[0] + 1, 0);
  1536.         lowcase (itok);
  1537.         treeinsert (ichartosstr (itok, 1), ICHARTOSSTR_SIZE, 1);
  1538.         }
  1539.         else if (contextbufs[0][0] == '#')
  1540.         {
  1541.         treeoutput ();
  1542.         math_mode = 0;
  1543.         LaTeX_Mode = 'P';
  1544.         }
  1545.         else if (contextbufs[0][0] == '!')
  1546.         terse = 1;
  1547.         else if (contextbufs[0][0] == '%')
  1548.         terse = 0;
  1549.         else if (contextbufs[0][0] == '-')
  1550.         {
  1551.         math_mode = 0;
  1552.         LaTeX_Mode = 'P';
  1553.         tflag = 0;
  1554.         }
  1555.         else if (contextbufs[0][0] == '+')
  1556.         {
  1557.         math_mode = 0;
  1558.         LaTeX_Mode = 'P';
  1559.         tflag = strcmp (&contextbufs[0][1], "nroff") != 0
  1560.           &&  strcmp (&contextbufs[0][1], "troff") != 0;
  1561.         }
  1562.         else if (contextbufs[0][0] == '~')
  1563.         {
  1564.         defdupchar = findfiletype (&contextbufs[0][1], 1, (int *) NULL);
  1565.         if (defdupchar < 0)
  1566.             defdupchar = 0;
  1567.         }
  1568.         else
  1569.         {
  1570.         if (contextbufs[0][0] == '^')
  1571.             {
  1572.             /* Strip off leading uparrow */
  1573.             for (cp1 = contextbufs[0], cp2 = contextbufs[0] + 1;
  1574.               (*cp1++ = *cp2++) != '\0';
  1575.               )
  1576.             ;
  1577.             contextoffset++;
  1578.             }
  1579.         checkline (stdout);
  1580.         }
  1581.         }
  1582.     if (hadnl)
  1583.         contextoffset = 0;
  1584.     else
  1585.         contextoffset += bufsize;
  1586. #ifndef USG
  1587.     if (sflag)
  1588.         {
  1589.         stop ();
  1590.         if (fflag)
  1591.         {
  1592.         rewind (stdout);
  1593.         (void) creat (askfilename, 0666);
  1594.         }
  1595.         }
  1596. #endif
  1597.     }
  1598.     }
  1599.  
  1600. /* Copy/ignore "cnt" number of characters pointed to by *cc. */
  1601. void copyout (cc, cnt)
  1602.     register char **    cc;
  1603.     register int    cnt;
  1604.     {
  1605.  
  1606.     while (--cnt >= 0)
  1607.     {
  1608.     if (**cc == '\0')
  1609.         break;
  1610.     if (!aflag && !lflag)
  1611.         (void) putc (**cc, outfile);
  1612.     (*cc)++;
  1613.     }
  1614.     }
  1615.  
  1616. static void lookharder (string)
  1617.     char *        string;
  1618.     {
  1619.     char        cmd[150];
  1620.     char        grepstr[100];
  1621.     register char *    g;
  1622.     register char *    s;
  1623. #ifndef REGEX_LOOKUP
  1624.     register int    wild = 0;
  1625. #ifdef LOOK
  1626.     static int        look = -1;
  1627. #endif /* LOOK */
  1628. #endif /* REGEX_LOOKUP */
  1629.  
  1630.     g = grepstr;
  1631.     for (s = string; *s != '\0'; s++)
  1632.     {
  1633.     if (*s == '*')
  1634.         {
  1635. #ifndef REGEX_LOOKUP
  1636.         wild++;
  1637. #endif /* REGEX_LOOKUP */
  1638.         *g++ = '.';
  1639.         *g++ = '*';
  1640.         }
  1641.     else
  1642.         *g++ = *s;
  1643.     }
  1644.     *g = '\0';
  1645.     if (grepstr[0])
  1646.     {
  1647. #ifdef REGEX_LOOKUP
  1648.     regex_dict_lookup (cmd, grepstr);
  1649. #else /* REGEX_LOOKUP */
  1650. #ifdef LOOK
  1651.     /* now supports automatic use of look - gms */
  1652.     if (!wild && look)
  1653.         {
  1654.         /* no wild and look(1) is possibly available */
  1655.         (void) sprintf (cmd, "%s %s %s", LOOK, grepstr, WORDS);
  1656.         if (shellescape (cmd))
  1657.         return;
  1658.         else
  1659.         look = 0;
  1660.         }
  1661. #endif /* LOOK */
  1662.     /* string has wild card chars or look not avail */
  1663.     if (!wild)
  1664.         (void) strcat (grepstr, ".*");    /* work like look */
  1665.     (void) sprintf (cmd, "%s ^%s$ %s", EGREPCMD, grepstr, WORDS);
  1666.     (void) shellescape (cmd);
  1667. #endif /* REGEX_LOOKUP */
  1668.     }
  1669.     }
  1670.  
  1671. #ifdef REGEX_LOOKUP
  1672. static void regex_dict_lookup (cmd, grepstr)
  1673.     char *        cmd;
  1674.     char *        grepstr;
  1675.     {
  1676.     char *        rval;
  1677.     int            whence = 0;
  1678.     int            quitlookup = 0;
  1679.     int            count = 0;
  1680.     int            ch;
  1681.  
  1682.     (void) sprintf (cmd, "^%s$", grepstr);
  1683.     while (!quitlookup  &&  (rval = do_regex_lookup (cmd, whence)) != NULL)
  1684.     {
  1685.     whence = 1;
  1686.         (void) printf ("%s\r\n", rval);;
  1687.     if ((++count % (li - 1)) == 0)
  1688.         {
  1689.         inverse ();
  1690.         (void) printf (CORR_C_MORE_PROMPT);
  1691.         normal ();
  1692.         (void) fflush (stdout);
  1693.         if ((ch = GETKEYSTROKE ()) == 'q'
  1694.           ||  ch == 'Q'  ||  ch == 'x'  ||  ch == 'X' )
  1695.              quitlookup = 1;
  1696.         /*
  1697.          * The following line should blank out the -- more -- even on
  1698.          * magic-cookie terminals.
  1699.          */
  1700.         (void) printf (CORR_C_BLANK_MORE);
  1701.         (void) fflush (stdout);
  1702.         }
  1703.     }
  1704.     if ( rval == NULL )
  1705.     {
  1706.     inverse ();
  1707.     (void) printf (CORR_C_END_LOOK);
  1708.     normal ();
  1709.     (void) fflush (stdout);
  1710.     (void) GETKEYSTROKE ();    
  1711.     }
  1712.     }
  1713.  
  1714. #endif /* REGEX_LOOKUP */
  1715.